// 处理序列化、反序列化以及封装解析的文件
#pragma once

#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>

const std::string blank_space_sep = " ";
const std::string protocol_sep = "\n";

// 封装报头和报文之间的分隔符
//"len\n_x op _y"
std::string Encode(const std::string &content)
{
    std::string package = std::to_string(content.size());
    package += protocol_sep;
    package += content;
    package += protocol_sep;

    return package;
}
// 解析去掉报头和报文之间的分隔符
// 移除解析过的报文
//"len\n_x op _y"
bool Decode(std::string &package, std::string *content)
{
    // 截取len
    size_t pos = package.find(protocol_sep);
    if (pos == std::string::npos)
        return false;
    std::string len_str = package.substr(0, pos);
    size_t len = std::stoi(len_str);

    // 判断报文是否合法
    size_t total_len = len_str.size() + len + 2;
    if (total_len > package.size())
        return false;

    // 获取content
    *content = package.substr(pos + 1, len);
    // 如果是一个完整的报文，那么会把content返回，同时移除该报文
    package.erase(0, total_len);
    return true;
}

class Request
{
public:
    Request(int x, int y, char op)
        : _x(x), _y(y), _op(op)
    {
    }
    Request()
    {
    }
    ~Request()
    {
    }

public:
    // 序列化
    bool Serialize(std::string *out)
    {
#ifdef MySelf
        // 有效载荷:"_x + _y"
        std::string s = std::to_string(_x);
        s += blank_space_sep;
        s += _op;
        s += blank_space_sep;
        s += std::to_string(_y);

        *out = s;
        return true;
#else
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["op"] = _op;

        Json::FastWriter w;
        *out = w.write(root);
        return true;
#endif
    }

    // 反序列化
    bool Deserialize(const std::string &in)
    {
#ifdef MySelf
        // 截取_x值
        size_t x_right = in.find(blank_space_sep);
        if (x_right == std::string::npos)
            return false;
        std::string x = in.substr(0, x_right);

        // 截取_y值
        size_t y_left = in.rfind(blank_space_sep);
        if (y_left == std::string::npos)
            return false;
        std::string y = in.substr(y_left + 1);

        if (x_right + 2 != y_left)
            return false;
        _op = in[x_right + 1];
        _x = std::stoi(x);
        _y = std::stoi(y);
        return true;
#else
        Json::Value root;
        Json::Reader r;
        r.parse(in, root);
        
        _x = root["x"].asInt();
        _y = root["y"].asInt();
        _op = root["op"].asInt();
        return true;
#endif
    }

public:
    int _x;
    int _y;
    char _op;
};

class Response
{
public:
    Response(int result, int code)
        : _result(result), _code(code)
    {
    }
    Response()
    {
    }
    ~Response()
    {
    }

public:
    bool Serialize(std::string *out)
    {
#ifdef MySelf
        // 报文："len\nresult code"
        // 有效载荷："result code"
        std::string s = std::to_string(_result);
        s += blank_space_sep;
        s += std::to_string(_code);

        *out = s;
        return true;
#else
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;

        Json::FastWriter w;
        *out = w.write(root);
        return true;
#endif
    }
    bool Deserialize(const std::string &in)
    {
#ifdef MySelf
        // 截取result
        size_t res_right = in.find(blank_space_sep);
        if (res_right == std::string::npos)
            return false;
        std::string res = in.substr(0, res_right);

        // 截取code
        size_t code_left = in.rfind(blank_space_sep);
        if (code_left == std::string::npos)
            return false;
        std::string code = in.substr(code_left + 1);

        if (res_right != code_left)
            return false;
        _result = std::stoi(res);
        _code = std::stoi(code);
        return true;
#else
        Json::Value root;
        Json::Reader r;
        r.parse(in, root);

        _result = root["result"].asInt();
        _code = root["code"].asInt();
        return true;
#endif
    }

public:
    int _result;
    int _code;
};

//使用Json::StyleWriter也可以，虽然他里面的有效载荷有\n，但是我们并不是以\n作为区分的，而是用len